import threading
import socket
import json
import websocket
import psutil
import PyHook3
import pythoncom
import win32api
import win32con
import os

import setting


class pywebsocket(threading.Thread):
    def __init__(self,ip,web_sock_send):
        threading.Thread.__init__(self)
        self.web_sock_send = web_sock_send
        websocket.enableTrace(True)
        self.web_sock = websocket.WebSocketApp("ws://" + ip,on_open=self.on_open,on_message=self.on_message,on_error=self.on_error,on_close=self.on_close)

    def run(self):
        self.web_sock.run_forever()
        self.web_sock_send.put({'type':'exit','msg':'pywebsocket'})
        print('pywebsocket: exit')

    def on_message(self,ws, message):
        _dict = json.loads(message)
        if _dict['type'] == 'logon':
            if _dict['msg'] == '登录成功':
                self.web_sock_send.put({'type':'logon','msg':'successful'})
                ws.send(return_msg())
            else:
                self.web_sock_send.put({'type':'logon','msg':'failure'})
        else:
            # print(_dict)
            self.web_sock_send.put({'type':_dict['type'],'msg':_dict['msg']})

    def on_error(self,ws, error):
        if error.errno == 10060:
            self.web_sock_send.put({'type':'logon','msg':'failure'})
        elif error.errno == 10054:
            self.web_sock_send.put({'type':'webclose'})

    def on_close(self,ws,close_status_code=None, close_msg=None):
        print('close: ',close_status_code, close_msg)

    def on_open(self,ws):
        ws.send(return_msg(login=False))


class pyhookstart(threading.Thread):
    def __init__(self,sock_send):
        threading.Thread.__init__(self)
        self.hm = PyHook3.HookManager()
        self.app = set()
        self.sock_send = sock_send

    def run(self):
        self.hm.KeyDown = self.onKeyboardEvent
        self.hm.KeyUp = self.onKeyboardEvent
        self.hm.HookKeyboard()
        pythoncom.PumpMessages()
        print('pyhookstart: exit')

    def _append(self,p):
        self.app.add(p)

    def _delete(self,p):
        if p in self.app:
            self.app.remove(p)

    def _thrstop(self,dentm):
        self.hm.UnhookKeyboard()
        win32api.PostThreadMessage(dentm,win32con.WM_QUIT,0,0)

    def onKeyboardEvent(self,event):
        if event.WindowName in self.app:
            if event.MessageName == "key down":
                self.sock_send.put({'type':'key_down','app':event.WindowName,'key':str(event.KeyID)})
            elif event.MessageName == "key up":
                self.sock_send.put({'type':'key_up','app':event.WindowName,'key':str(event.KeyID)})
            ret = False
        else:
            ret = True
        return ret


class web_send(threading.Thread):
    def __init__(self,web_sock_recv,window):
        threading.Thread.__init__(self)
        self.web_sock_recv = web_sock_recv
        self.window = window

    def run(self):
        while True:
            dic = self.web_sock_recv.get(True)
            if dic['type'] == 'send':
                self.window.web_sock.send(return_msg_dict(dic['data']))
            elif dic['type'] == 'close':
                self.window.web_sock.close()
                self.window.web_sock_send.put({'type':'close'})
                print('web_send: exit')
                break


class sok_send(threading.Thread):
    def __init__(self,sock_recv,window):
        threading.Thread.__init__(self)
        self.sock_recv = sock_recv
        self.window = window

    def run(self):
        while True:
            dic = self.sock_recv.get(True)
            if dic['type'] == 'add':
                self.window._append(dic['app'])
            elif dic['type'] == 'del':
                self.window._delete(dic['app'])
            elif dic['type'] == 'close':
                self.window._thrstop(self.window.ident)
                self.window.sock_send.put({'type':'close'})
                print('sok_send: exit')
                break


def ret_prot():
    net_con = psutil.net_connections()
    run_prot = [i.laddr.port for i in net_con]
    for pr in range(9001,9111):
        if pr not in run_prot:
            return pr
    return None


def isrun(isr=None):
    net_con = psutil.net_connections()
    run_prot = [i.laddr.port for i in net_con]
    if 9678 not in run_prot:
        return False
    else:
        try:
            client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
            client.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
            client.connect(('127.0.0.1',9678))
            if not isr:
                client.send(json.dumps({"msg":"isrun"}).encode('utf-8'))
            else:
                client.send(json.dumps({"msg":"close"}).encode('utf-8'))
            msg = client.recv(1024)
            client.close()
            jsmsg = json.loads(msg)
            if jsmsg['msg'] == "run":
                sum = 0
                apps = []
                pidsl = psutil.pids()
                if os.getpid() in pidsl:
                    pidsl.remove(os.getpid())
                if os.getppid() in pidsl:
                    pidsl.remove(os.getppid())
                for i in pidsl:
                    try:
                        if jsmsg['name'] == psutil.Process(i).name():
                            sum += 1
                            apps.append(i)
                    except:
                        pass
                if sum == 3:
                    return True
                else:
                    for i in apps:
                        os.system('taskkill -f -pid ' + str(i))
                    return False
            else:
                return False
        except:
            return False


def socketrun(web_sock_send,name):
    tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    tcp_server.bind(('127.0.0.1',9678))
    tcp_server.listen(5)
    while True:
        try:
            new_socket, client_addr = tcp_server.accept()
            messg = new_socket.recv(1024)
            jsmsg = json.loads(messg)
            if jsmsg['msg'] == 'isrun':
                web_sock_send.put({'type':'isrun','msg':'show'})
                new_socket.send(json.dumps({"msg":"run","name":name}).encode('utf-8'))
            elif jsmsg['msg'] == 'close':
                new_socket.send(json.dumps({"msg":"ok"}).encode('utf-8'))
                new_socket.close()
                break
            new_socket.close()
        except:
            pass
    tcp_server.close()	


def return_msg(msg=None,login=True,report=False,typ='get-list',lis=[]):
    msg_dict = {
        'lgon': login,
        'user': 'root',
        'type': typ,
        'msg': msg,
        'report': report,
        'model': setting.MYCONFIG.ffffffffffffffff,
        'list':lis
    }
    return json.dumps(msg_dict)


def return_msg_dict(dic):
    msg_dict = {
        'lgon': True,
        'user': 'root',
        'type': 'str',
        'msg': None,
        'report': False,
        'model': setting.MYCONFIG.ffffffffffffffff,
        'list':[]
    }
    for it in msg_dict:
        if it in dic:
            msg_dict.update({it:dic[it]})
    return json.dumps(msg_dict)


def return_send(typ='move', x=0, y=0, flag=None):
    msg_dict = {
        'type': typ,
        'x':x,
        'y':y,
        'falg':flag
    }
    return json.dumps(msg_dict)